﻿namespace PokerSimulator
{
	using System;
	using System.Collections.Generic;
	using System.Diagnostics;
	using System.Threading.Tasks;
	using PugLib.Benchmarks;
	using PugLib.Extensions.Collections;

	internal class Run
	{
		private static void Main()
		{
			TestResultCollection testResults = new TestResultCollection();

			const int million = 1000000;

			testResults.Add(RunSimulation(GameType.TexasHoldEm, 5, 1*million));

			Console.WriteLine();
			Console.WriteLine(testResults);
			Console.WriteLine();

			Console.WriteLine("...done");
		}

		private static TestResult RunSimulation(GameType gameType, int playerCount, int gamesToPlay)
		{
			string name = string.Concat("Game: ", gameType, ", Players: ", playerCount, ", Games: ", gamesToPlay);
			Console.WriteLine(name);
			Stopwatch stopwatch = new Stopwatch();
			stopwatch.Start();
			///////////////////////////////////            
			RunGameBatch(gameType, playerCount, gamesToPlay);
			///////////////////////////////////
			stopwatch.Stop();
			TestResult trd = new TestResult(name);
			trd.Duration = stopwatch.Elapsed.TotalSeconds;
			return trd;
		}

		private static void RunGameBatch(GameType gameType, int playerCount, int gamesToPlay)
		{
			GameBatchParameters parameters = CreateGameBatchParameters(gamesToPlay);

			Log[] logs = new Log[parameters.MaxLoopCount];
			try
			{
				Parallel.For(0, parameters.MaxLoopCount, gameCount =>
				{
					Game game = Game.Create(gameType, playerCount);
					game.GamesToPlay = parameters.GamesPerInstance;
					game.VerboseLogging = false;
					parameters.ApproximateErrorGameIteration = gameCount;
					logs[gameCount] = game.Run();
					Log.ReportProgress(gameCount, parameters.StatusCount, gamesToPlay);
				});
			}
			catch (OutOfMemoryException)
			{
				Console.WriteLine("Out of memory after approximately" + parameters.ApproximateErrorGameIteration + " iterations.");
				Console.ReadKey();
			}

			Game gameSum = Game.Create(gameType, playerCount);
			gameSum.GamesToPlay = gamesToPlay;
			gameSum.Log = MergeLogs(logs);
			Game.ReportGame(gameSum);
		}

		private static GameBatchParameters CreateGameBatchParameters(int gamesToPlay)
		{
			GameBatchParameters parameters = new GameBatchParameters();
			parameters.GamesToPlay = gamesToPlay;
			parameters.StatusCount = Convert.ToInt64((gamesToPlay*.05f));
			parameters.GamesPerInstance = 1000;

			// set up da loops     
			if (parameters.GamesToPlay <= parameters.GamesPerInstance)
			{
				parameters.MaxLoopCount = 1;
				parameters.GamesPerInstance = parameters.GamesToPlay;
			}
			else
			{
				parameters.MaxLoopCount = parameters.GamesToPlay/parameters.GamesPerInstance;
			}
			return parameters;
		}

		private static Log MergeLogs(IList<Log> logs)
		{
			Log merged = new Log();
			logs.ForEach(merged.AddLog);
			return merged;
		}
	}
}